package com.runnor.common.websys.system.config;

import cn.hutool.core.exceptions.ExceptionUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.jwt.JWTUtil;
import com.runnor.common.websys.system.entity.ApiResult;
import com.runnor.common.websys.system.entity.SysLog;
import com.runnor.common.websys.system.service.SysLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

/**
 * @author runnor-yh
 * @date 2023年08月15日 17:04
 */

@Component
@Aspect
@Slf4j
public class LogAspect {
    @Autowired
    SysLogService logService;

    // 引入日志。切面
    @Pointcut("execution(public * com.runnor.common.websys.*.controller..*.*(..))")
    public void logcut() {
    }

    @Around("logcut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        SysLog accessLog = new SysLog();

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        accessLog.setHttpPath(request.getRequestURI());
        accessLog.setHttpMethod(request.getMethod());
        accessLog.setRemoteAddr(getIpAddr(request));
        accessLog.setUserAgent(request.getHeader("User-Agent"));
        String authorization = request.getHeader("Authorization");
        if (StrUtil.isNotBlank(authorization)) {
            JSONObject payloads = JWTUtil.parseToken(authorization).getPayloads();
            String userid = StrUtil.toStringOrNull(payloads.get("userid"));
            String username = StrUtil.toStringOrNull(payloads.get("username"));
            accessLog.setUserid(userid);
            accessLog.setUsername(username);
        }
        String methodName = point.getSignature().toShortString();
        accessLog.setJavaMethodName(methodName);

        Object[] args = point.getArgs();
        String[] parameterNames = ((MethodSignature) point.getSignature()).getParameterNames();
        if (parameterNames != null && parameterNames.length > 0) {
            JSONObject requestParams = new JSONObject();
            for (int i = 0; i < parameterNames.length; i++) {
                requestParams.putOpt(parameterNames[i], args[i]);
            }
            accessLog.setReqParam(requestParams.toString());
        }
        long startTs = System.currentTimeMillis();
        try {
            Object result = point.proceed();
            if (result instanceof ResponseEntity) {
                if ((((ResponseEntity) result).getBody()) instanceof ApiResult) {
                    ((ApiResult) (((ResponseEntity) result).getBody())).setT(request.getParameter("t"));
                }
                accessLog.setRespData(JSONUtil.toJsonStr(((ResponseEntity) result).getBody()));
            } else {
                accessLog.setRespData(JSONUtil.toJsonStr(result));
            }
            return result;
        } catch (Exception e) {
//            log.error(e());
            accessLog.setException(ExceptionUtil.stacktraceToString(e, 2147483647));
            e.printStackTrace();
            return ResponseEntity.ok(ApiResult.error(e));
        } finally {
            Long cost = System.currentTimeMillis() - startTs;
            accessLog.setCost(cost.intValue());
            logService.save(accessLog);
        }
    }


    private String getIpAddr(HttpServletRequest request) {
        String ip = null;

        // X-Forwarded-For：Squid 服务代理
        String ipAddresses = request.getHeader("X-Forwarded-For");
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            // Proxy-Client-IP：apache 服务代理
            ipAddresses = request.getHeader("Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            // WL-Proxy-Client-IP：weblogic 服务代理
            ipAddresses = request.getHeader("WL-Proxy-Client-IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            // HTTP_CLIENT_IP：有些代理服务器
            ipAddresses = request.getHeader("HTTP_CLIENT_IP");
        }
        if (ipAddresses == null || ipAddresses.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            // X-Real-IP：nginx服务代理
            ipAddresses = request.getHeader("X-Real-IP");
        }

        // 有些网络通过多层代理，那么获取到的ip就会有多个，一般都是通过逗号（,）分割开来，并且第一个ip为客户端的真实IP
        if (ipAddresses != null && ipAddresses.length() != 0) {
            ip = ipAddresses.split(",")[0];
        }

        // 还是不能获取到，最后再通过request.getRemoteAddr();获取
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ipAddresses)) {
            ip = request.getRemoteAddr();
        }
        return ip.equals("0:0:0:0:0:0:0:1") ? "127.0.0.1" : ip;
    }
}
